﻿using System;
using System.Collections;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Bronze.Network;
using System.Collections.Generic;

namespace Bronze.XXT.PhoneServer
{
    public class Server
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        private int m_iSeqID = 1;
        private int clientTimeoutSeconds;

        /// <summary>
        /// 发送数据超时的时间（秒）
        /// </summary>
        public int SendTimeout
        {
            get { return clientTimeoutSeconds; }
            set { clientTimeoutSeconds = value; }
        }
        private int clientConnectionTimeoutSeconds;

        /// <summary>
        /// 连接初始化超时的时间（秒）
        /// </summary>
        public int ConnectionTimeout
        {
            get { return clientConnectionTimeoutSeconds; }
            set { clientConnectionTimeoutSeconds = value; }
        }

        private int activeTestInterval = 3 * 60;
        /// <summary>
        /// 激活测试的间隔时间
        /// </summary>
        public int ActiveTestInterval
        {
            get { return activeTestInterval; }
            set { activeTestInterval = value; }
        }

        private int maxRetryCount = 2;

        public int MaxRetryCount
        {
            get { return maxRetryCount; }
            set { maxRetryCount = value; }
        }
        

        private object lockobject = new object();
        private CommonServer svr;
        private System.Timers.Timer timer1;

        public event SocketHandle ClientClose;

        public event SocketHandle ClientConnect;

        public event SocketHandle ReceiveData;

        public Server(int port)
        {
            this.timer1 = new System.Timers.Timer();
            this.timer1.Interval = 10 * 1000;
            this.timer1.Elapsed += new System.Timers.ElapsedEventHandler(timer1_Elapsed);
            this.timer1.Start();
            this.svr = new CommonServer(port);
            this.svr.OnDataIn += new OnDataInHandler(this.svr_OnDataIn);
            this.svr.OnDisconnected += new OnDisconnectedHandler(this.svr_OnDisconnected);
        }



        public void Start()
        {
            this.svr.Start();
        }

        public void Stop()
        {
            this.timer1.Stop();
            this.svr.Shutdown();
        }

        public void Send(ClientConnection connection, byte[] data)
        {
            this.svr.Send(connection.ConnectionId, data);
            connection.LastSendTime = DateTime.Now;
        }

        private void svr_OnDataIn(object sender, SocketDataInEventArgs e)
        {
            int connectionId = e.ConnectionId;

            byte[] bytes = e.Data;
            DateTime now = DateTime.Now;

            var messages = Message.FromBytes(bytes, true);
            if (bytes.Length > 0 && messages.Count > 0)
            {
                e.Connection.LastReciveTime = DateTime.Now;

                if (e.Connection.ClientStatus == ClientStatus.Unknown)
                {
                    //触发新话机连接到服务器的事件
                    if (this.ClientConnect != null)
                    {
                        this.ClientConnect(this, new PhoneEventArgs(e.Connection, messages, ""));
                    }
                }
                

                //处理消息
                foreach (var msg in messages)
                {
                    //话机认证请求
                    if (msg.func_no == Const.PHONE_AUTHEN)
                    {
                        var response = new Message()
                        {
                            seq_no = msg.seq_no,
                            Body = new PHONE_AUTHEN_Response()
                            {
                                //TODO 需要重本地数据库里面验证该话机是否已经注册
                                valid_flag = "1"
                            }
                        };

                        var request = new Message()
                        {
                            seq_no = CreateSeqId(),
                            Body = new ABT_STATUS_Request() { }
                        };

                        var sendBytes = Message.MessagesToBytes(response, request);
                        e.Connection.LastSendActiveTestTime = DateTime.Now;
                        Send(e.Connection, sendBytes);

                        var body = msg.Body as PHONE_AUTHEN_Request;
                        e.Connection.Tag = body.DeviceId;

                        //检查是否有多余的无效连接，并关闭
                        lock (this.lockobject)
                        {
                            foreach (DictionaryEntry entry in svr.ClientConnections)
                            {
                                var client = entry.Value as ClientConnection;
                                if (client == e.Connection) continue;
                                if ((body.DeviceId.Equals(client.Tag)))
                                {
                                    log.InfoFormat("Will关闭一个空闲的连接{0},当前连接:{1},所属设备ID:{2}",client.ConnectionId, e.ConnectionId, body.DeviceId);
                                    client.ClientStatus = ClientStatus.Offline;
                                    
                                }
                            }
                        }

                        FireReceiveData(new PhoneEventArgs(e.Connection, msg, "话机连接"));
                        break;
                    }

                    //网络连接查询请求
                    else if (msg.func_no == Const.CONNECT_STATUS)
                    {
                        var response = new Message()
                        {
                            seq_no = msg.seq_no,
                            Body = new CONNECT_STATUS_Response() { }
                        };
                        var sendBytes = Message.MessagesToBytes(response);

                        Send(e.Connection, sendBytes);
                    }

                    //话机向服务器回复话机状态信息
                    else if (msg.func_no == Const.ABT_STATUS)
                    {
                        //TODO 把话机连接状态和版本信息写入数据库
                        e.Connection.ClientStatus = ClientStatus.Online;
                        e.Connection.LastActiveTestResponseTime = DateTime.Now;
                        e.Connection.RetryCount = 0;
                        FireReceiveData(new PhoneEventArgs(e.Connection, msg, "话机状态查询"));
                    }

                    //刷卡签到
                    else if (msg.func_no == Const.STDT_SIGN_RECS)
                    {
                        var response = new Message()
                        {
                            seq_no = msg.seq_no,
                            Body = new STDT_SIGN_RECS_Response() { valid_flag = "1" }
                        };
                        var sendBytes = Message.MessagesToBytes(response);
                        Send(e.Connection, sendBytes);

                        FireReceiveData(new PhoneEventArgs(e.Connection, msg, "收到新刷卡签到信息"));
                    }

                    //学生卡登录
                    else if (msg.func_no == Const.STDT_CARD_LOGIN)
                    {
                        //TODO 注意判断学生和教师卡的情况
                        var body = new STDT_CARD_LOGIN_Response();
                        body.valid_flag = "1";
                        body.Family_num = "2";
                        body.Family_msisdn = new List<string>() { "15990005880", "10086" };
                        body.Family_relation = new List<string>() { "哥哥", "姐姐" };

                        var response = new Message()
                        {
                            seq_no = msg.seq_no,
                            Body = body
                        };

                        var sendBytes = Message.MessagesToBytes(response);
                        Send(e.Connection, sendBytes);

                        FireReceiveData(new PhoneEventArgs(e.Connection, msg, "收到学生卡登录"));
                    }
					else
					{
						log.InfoFormat("###未处理的消息func_no={0}",msg.func_no);
					}
                }

            }
            else
            {
                e.Connection.ClientStatus = ClientStatus.Offline;
                log.InfoFormat("接收数据包异常-强制关闭{0}", e.Connection.ConnectionId);
                FireClientClose(new PhoneEventArgs(e.Connection, null, "接收数据包异常-强制关闭"));
                this.svr.Disconnect(connectionId);
            }
        }

        private void FireReceiveData(PhoneEventArgs e)
        {
            if (this.ReceiveData != null)
            {
                this.ReceiveData(this, e);
            }
        }


        private void FireClientClose(PhoneEventArgs e)
        {
            try
            {
                if (this.ClientClose != null)
                {
                    this.ClientClose(this, e);
                }
            }
            catch(Exception ex)
            {
                log.Error("关闭连接时异常", ex);
            }
        }

        private void svr_OnDisconnected(object sender, SocketDisconnectedEventArgs e)
        {
            if (e.Connection == null)
            {
                return;
            }
            e.Connection.ClientStatus = ClientStatus.Offline;
            this.FireClientClose(new PhoneEventArgs(e.Connection));
        }

        private void timer1_Tick(object sender, EventArgs e)
        {

        }

        private void SendActiveTest(ClientConnection conn)
        {
            var request = new Message()
            {
                seq_no = CreateSeqId(),
                Body = new ABT_STATUS_Request() { }
            };

            var sendBytes = Message.MessagesToBytes(request);
            Send(conn, sendBytes);
            conn.LastSendActiveTestTime = DateTime.Now;
        }

        void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            timer1.Enabled = false;
            try
            {
                lock (this.lockobject)
                {
                    foreach (DictionaryEntry entry in svr.ClientConnections)
                    {
                        var client = entry.Value as ClientConnection;
                        TimeSpan span = (TimeSpan)(DateTime.Now - client.LastSendTime);

                        var close= client.CheckShouldDisconnection(this.ConnectionTimeout,this.SendTimeout);
                        if (close)
                        {
                            client.ClientStatus = ClientStatus.Offline;
                        }

                        if (client.ClientStatus == ClientStatus.Online)
                        {
                            TimeSpan activeSendSpan = (TimeSpan)(DateTime.Now - client.LastSendActiveTestTime);
                            if (client.LastSendActiveTestTime > client.LastActiveTestResponseTime)
                            {
                                if (activeSendSpan.TotalSeconds > this.SendTimeout)
                                {
                                    if (client.RetryCount < MaxRetryCount)
                                    {
                                        client.RetryCount++;
                                        this.SendActiveTest(client);
                                        log.InfoFormat("激活测试失败{0}，重试{1}次", client.ConnectionId, client.RetryCount);
                                        log.InfoFormat("重新发送激活测试{0}", client.ConnectionId);
                                    }
                                    else
                                    {
                                        client.ClientStatus = ClientStatus.Offline;
                                        log.InfoFormat("激活测试失败{0}，应该关闭连接", client.ConnectionId);
                                    }
                                }
                            }
                            else
                            {
                                if (activeSendSpan.TotalSeconds > this.ActiveTestInterval)
                                {
                                    this.SendActiveTest(client);
                                    log.InfoFormat("发送激活测试{0}", client.ConnectionId);
                                }
                            }
                        }
                        

                        if (client.ClientStatus == ClientStatus.Offline)
                        {
                        	log.InfoFormat("强制关闭连接{0}",client.ConnectionId);
                            FireClientClose(new PhoneEventArgs(client, null, "强制关闭"));
                            svr.Disconnect(client.ConnectionId);
                        }

                    }
                }
            }
            catch
            {
            }
            finally
            {
                timer1.Enabled = true;
            }
        }

        protected string CreateSeqId()
        {
            int id = m_iSeqID;
            Interlocked.Increment(ref m_iSeqID);
            if (m_iSeqID > 9999)
                m_iSeqID = 1;
            return id.ToString().PadLeft(4, '0');
        }
    }

    public class Connection
    {
        public int Id;
        public string Text;
        public string Device_id;
        public override string ToString()
        {
            return Text;
        }
    }

    public delegate void SocketHandle(object sender, PhoneEventArgs e);
}

